package com.tbit.utils;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author MyWin E-mail:335918956@qq.com
 * @version 1.0
 * @createTime 2018/9/28 0028 13:58
 */
public abstract class BaseDelayBatUpdateHandle<K, V> implements Runnable {
    /**
     * 数据缓冲集合
     */
    private LinkedHashMap<K, ValueWrapper<V>> _list;
    private ReentrantLock _listSync = new ReentrantLock();
    private boolean running;
    private boolean active;
    /**
     * 检测的时间间隔
     */
    private int checkInvMs;
    /**
     * 处理的时间间隔
     */
    private int handleDelay;
    /**
     * 是否自动启动
     */
    private boolean autoStart;

    public BaseDelayBatUpdateHandle() {
        this._list = new LinkedHashMap<>();
    }

    public boolean isRunning() {
        return running;
    }

    public int getCheckInvMs() {
        return checkInvMs;
    }

    public void setCheckInvMs(int checkInvMs) {
        this.checkInvMs = checkInvMs;
    }

    public int getHandleDelay() {
        return handleDelay;
    }

    public void setHandleDelay(int handleDelay) {
        this.handleDelay = handleDelay;
    }

    public boolean isAutoStart() {
        return autoStart;
    }

    public void setAutoStart(boolean autoStart) {
        this.autoStart = autoStart;
        if (this.autoStart) {
            this.start();
        }
    }

    @Override
    public void run() {
        try {
            running = true;
            while (active) {
                try {
                    checkHandleItem();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    try {
                        Thread.sleep(checkInvMs);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        } finally {
            running = false;
        }
    }

    public abstract void handleItems(LinkedList<V> list);

    public void addItem(K k, V v) {
        try {
            _listSync.lock();

            if (_list.containsKey(k)) {
                _list.get(k).setValue(v);
            } else {
                _list.put(k, new ValueWrapper<V>(v));
            }
        } finally {
            _listSync.unlock();
        }
    }

    private void checkHandleItem() {
        LinkedList<V> list = new LinkedList<>();
        LinkedList<K> delKeyList = new LinkedList<>();
        try {
            _listSync.lock();
            Set<Map.Entry<K, ValueWrapper<V>>> entrySet = _list.entrySet();
            for (Map.Entry<K, ValueWrapper<V>> entry : entrySet) {
                if (entry.getValue().checkDt(handleDelay)) {
                    list.addLast(entry.getValue().value);
                    delKeyList.addLast(entry.getKey());
                }
            }
            for (K key : delKeyList) {
                _list.remove(key);
            }
        } finally {
            _listSync.unlock();
        }
        if (!list.isEmpty()) {
            handleItems(list);
        }
    }

    public void stop() {
        active = false;
    }

    public void start() {
        active = true;
        if (!running) {
            new Thread(this).start();
        }
    }

    public class ValueWrapper<V> {
        private V value;
        private Long dt;

        public ValueWrapper(V value) {
            this.value = value;
            this.dt = System.currentTimeMillis();
        }

        public Long getDt() {
            return dt;
        }

        public V getValue() {
            return value;
        }

        public void setValue(V value) {
            this.value = value;
        }

        public boolean checkDt(int handleDelay) {
            return (System.currentTimeMillis() - dt) > handleDelay;
        }
    }
}
